﻿/********************************************************************************
** auth： Mine
** date： 2018/12/19 17:36:20
** desc： 文件部分复制:针对大文本日志截取的场景
** Ver.:  V1.0.0
*********************************************************************************/
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;

namespace pers.mine.utils
{
    class FilePartCopy
    {
        public  const long PART_SIZE_100M = (1 << 20) * 100;
        public  const long PART_SIZE_500M = (1 << 20) * 500;
        public  const long PART_SIZE_1K = (1 << 10);

        public  const Int16 COPY_TYPE_HEAD = 1;//头截取
        public  const Int16 COPY_TYPE_PART = 2;//等份截取
        public  const Int16 COPY_TYPE_TAIL = 3; //尾截取

        /// <summary>
        /// 开始，操作进度，结束 三个事件
        /// </summary>
        public event EventHandler startEvent;
        public event EventHandler processEvent;
        public event EventHandler partStartEvent;
        public event EventHandler partEndEvent;
        public event EventHandler endEvent;

        public string source { get; set; }
        public string targetPath { get; set; }
        public Int16 copyType { get; set; }
        public long partSize { get; set; }


        public List<String> errmsgs { get; private set; } //外部只读不可改,内部可读可改
        public long sourceLength { get; private set; }
        public long curCopyLength { get; private set; }

        public int curCopyPart { get; private set; }
        public String curCopyPartPathName { get; private set; }
        public long startCopyIndex { get; private set; }
        public long endCopyIndex { get; private set; }
        public int partCount { get; private set; }
        public FileInfo sourceFile  { get; private set; }
        /// <summary>
        /// 执行复制
        /// </summary>
        public void ExecuteCopy()
        {
            errmsgs = new List<String>();
            
            try
            {
                if (String.IsNullOrWhiteSpace(source))
                {
                    throw new Exception("来源文件未选择！");
                }
                //初始化复制信息

                FileInfo fi = new FileInfo(source);
                if (!fi.Exists)
                {
                    throw new Exception("来源文件不存在！");
                }
                sourceFile = fi;
                sourceLength = fi.Length;
                curCopyLength = 0;
                try
                {
                    DirectoryInfo targetDir = new DirectoryInfo(targetPath);
                    if (!targetDir.Exists)
                    {
                        targetPath = fi.Directory.FullName;
                    }
                }
                catch (Exception)
                {
                    targetPath = fi.Directory.FullName;
                }


                if (partSize <= 0 || partSize >= sourceLength)
                {
                    throw new Exception("[截取大小非法] 源文件大小:" + sourceLength+"b;截取大小:"+partSize+"b");
                }
                switch (copyType)
                {
                    case COPY_TYPE_HEAD:
                        {
                            this.startCopyIndex = 0;
                            this.endCopyIndex = partSize - 1;
                            this.partCount = 1;
                        } break;
                    case COPY_TYPE_PART:
                        {
                            this.startCopyIndex = 0;
                            this.endCopyIndex = sourceLength - 1;
                            this.partCount = (int)((sourceLength - 1) / partSize) + 1;
                        } break;
                    case COPY_TYPE_TAIL:
                        {
                            this.startCopyIndex = sourceLength - partSize;
                            this.endCopyIndex = sourceLength - 1;
                            this.partCount = 1;
                        } break;
                    default:
                        throw new Exception("复制类型参数非法！");
                }
                if (startEvent != null)
                {
                    startEvent.Invoke(this, new EventArgs());
                }

                //执行复制
               
                for (int i = 0; i < partCount; i++)
                {
                    long currStartIndex = startCopyIndex + (partSize * i);
                    long currEndIndex = startCopyIndex + partSize * (i + 1);
                    if (currEndIndex > endCopyIndex)
                    {
                        currEndIndex = endCopyIndex;
                    }
                    var currFilePathName = targetPath + Path.DirectorySeparatorChar + sourceFile.Name + "_Part_" + i;
                    this.curCopyPartPathName = currFilePathName;
                    this.curCopyPart = i;
                    if (partStartEvent!=null)
                    {
                        partStartEvent.Invoke(this, new EventArgs());
                    }
                    singleCopy(source, currFilePathName, currStartIndex, currEndIndex);
                    if (partEndEvent != null)
                    {
                        partEndEvent.Invoke(this, new EventArgs());
                    }
                }
            }
            catch (Exception e)
            {
                errmsgs.Add("发生异常:" + e.Message);
            }
            //结束复制
            if (endEvent != null)
            {
                Thread.Sleep(500);//暂停一会  
                endEvent.Invoke(this, new EventArgs());
            }
        }

        private void singleCopy(String sourceFilePathName, String targetFilePathName, long startIndex, long endIndex)
        {
            Stream instram = null;
            BufferedStream inbfs = null;
            Stream oustram = null;
            BufferedStream oubfs = null;
            try
            {
                instram = File.OpenRead(sourceFilePathName);
                inbfs = new BufferedStream(instram);
                oustram = File.OpenWrite(targetFilePathName);
                oubfs = new BufferedStream(oustram);
                byte[] buffer = new byte[1024];
                long tempReadLength = 0;
                
                inbfs.Seek(startIndex, SeekOrigin.Begin);//起始位置
                
                while ((tempReadLength = inbfs.Read(buffer, 0, buffer.Length)) > 0)
                {
                    oubfs.Write(buffer, 0, 1024);
                    curCopyLength += tempReadLength;
                    processEvent.Invoke(this, new EventArgs());
                    if (inbfs.Position > endIndex)
                    {
                        break;
                    }
                }
            }
            catch (Exception e)
            {
                errmsgs.Add(e.Message);
            }
            finally {
                try
                {
                    if (inbfs != null) inbfs.Flush();
                    if (oubfs != null) oubfs.Flush();
                    if (inbfs != null) inbfs.Close();
                    if (instram != null) instram.Close();
                    if (oubfs != null) oubfs.Close();
                    if (oustram != null) oustram.Close();
                }
                catch (Exception e)
                {
                    errmsgs.Add(e.Message);
                }
            }
        }
    }
}
